# -*- coding: utf-8 -*-

import sys
import os
try:
        import pygtk
        pygtk.require("2.0")
except:
        pass
try:
        import gtk
        import gtk.glade
except:
        sys.exit(1)
from simpledcpp.core.base import DCPPPart, DCPPEvent, with_psyco
from simpledcpp.gui.widgets.list import FileListTree
from simpledcpp.core.filelist.filelist import FileList
from simpledcpp.gui.base import gtk_lock_required
from xml.sax import make_parser
from xml.sax.handler import ContentHandler
from simpledcpp.gui.HumanReadableSize import HRS
from thread import start_new_thread

import psyco

class SaxHandler(ContentHandler):
        """ Callback class for SAX parser """
	def __init__(self):
		self.dir_stack = list()
		self.dir_stack.append('root')
		self.filelist = {}
		self.filelist['/root'] = list()
		self.chars = ""
		self._alternates = {}

	def _getCurPath(self):
		str = ""
		for i in self.dir_stack:
			str = str + '/' + i
		return str

        def startElement(self,name,attrs):
                """ Handle for element begin """
		if name == 'Directory':
			dirname = attrs.get('Name').encode('utf-8')
			append_elem = [0, dirname, '']
			try:
				if attrs.has_key('TTH'):
					append_elem.append(attrs.get('TTH').encode('utf-8'))
			except:
				print sys.exc_info()
				pass
			self.filelist[self._getCurPath()].append(append_elem)
			self.dir_stack.append(dirname)
			self.filelist[self._getCurPath()] = list()
		elif name == 'File':
			filename = attrs.get('Name').replace("&amp;","&").encode('utf-8')
			filesize = attrs.get('Size').encode('utf-8')
			filetth = attrs.get('TTH').encode('utf-8')
			self.filelist[self._getCurPath()].append([1, filename, filesize, filetth])
			self._alternates[filetth] = 1

        def endElement(self,name):
                """ Handle for finished element """
		if name == 'Directory':
			self.dir_stack.pop()

        def characters (self,ch):
                """ Handle for character data """
                sch = ch.lstrip()
                if not sch == "":
                        self.chars = sch


class NewStyleFileListPage(DCPPPart):
	""" Page for view filelists. """
	
	def GetIcon(self, type):
		gtk.gdk.threads_init()
		if self._icons.has_key(type.lower()):
			icon_name = self._icons[type.lower()]
		else:
			icon_name = self._icons['default']
		if self._icontheme.has_icon(icon_name):
			pixbuf = self._icontheme.load_icon(icon_name, 24, 0)
		else:
			pixbuf = self.tree.treeview.render_icon(gtk.STOCK_OPEN, gtk.ICON_SIZE_BUTTON)
		gtk.gdk.threads_leave()
		return pixbuf

	def __init__(self, parent, nickname, filename, expand = None):
		# initialize parent class
		DCPPPart.__init__(self, parent)
		self.__downloaddir = None
		self.__expand = expand
		self.__expanditer = None
		# Define icons
		self._icons = {
                'avi' : 'gnome-mime-video',
                'mov' : 'gnome-mime-video',
                'mpg' : 'gnome-mime-video',
                'mkv' : 'gnome-mime-video',
                'jpg' : 'gnome-mime-image-jpeg',
                'jpeg' : 'gnome-mime-image-jpeg',
                'gif' : 'gnome-mime-image-gif',
                'bmp' : 'gnome-mime-image-bmp',
                'png' : 'gnome-mime-image-png',
                'exe' : 'gnome-mime-application-x-executable',
                'bin' : 'gnome-mime-application-x-executable',
                'folder' : 'gnome-folder',
                'html' : 'gnome-html',
                'xhtml' : 'gnome-html',
                'rar' : 'gnome-mime-application-x-rar',
                'bz2' : 'gnome-mime-application-zip',
                'tar' : 'gnome-mime-application-zip',
                'gz' : 'gnome-mime-application-zip',
                'zip' : 'gnome-mime-application-zip',
                'iso' : 'gnome-mime-application-x-cd-image',
                'vcd' : 'gnome-mime-application-x-cd-image',
                'mdf' : 'gnome-mime-application-x-cd-image',
                'mp3' : 'gnome-mime-audio-x-mp3',
                'ogg' : 'gnome-mime-audio',
                'wav' : 'gnome-mime-audio',
                'flac' : 'gnome-mime-audio',
                'wma' : 'gnome-mime-audio',
                'mpeg' : 'gnome-mime-video',
                'wmv' : 'gnome-mime-video-x-ms-wmv',
                'txt' : 'text-plain',
                'doc' : 'document',
                'docx' : 'document',
		'default': 'gnome-folder',
		}
		# make human readable size object
		self.HRS = HRS()
		# set page fields
		self.name = _("Browse files") + " %s"%nickname
		self._nickname = nickname
		self.type = 'filelist'
		self._filename = filename
		# Make menu for own filelist and filelist of other users.
                if nickname != self.settings.get('nickname'):
                        self.menu_items = (
                         ( "/_" + _("Load selected"), "filelist", self.Download, 0, None ),
			 ( "/_" + _("Load selected to"), "loadto", self.DownloadTo, 0, None),
                         ( "/_" + _("Copy magnet-link to clipboard"), "Magnet", self._magnet, 0, None),
                        )
                else:
                        self.menu_items = (
                         ( "/_" + _("Copy magnet-link to clipboard"), "Magnet", self._magnet, 0, None),
                        )
		# Make tree
		self.tree = FileListTree(self.menu_items)
		# Get default icon theme
		self._icontheme = gtk.icon_theme_get_default()
		# Load filelist
		self._loadFileList(filename)
		# Make scrolled window
                sw = gtk.ScrolledWindow()
                sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		sw.add(self.tree.widget)
		sw.show()
		self._widget = sw


	def DownloadTo(self, *args, **kwargs):
                self._dialog = gtk.FileChooserDialog(_("Select directory"),
                                        parent = self.parent.window,
                                        action = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
                                        buttons = (gtk.STOCK_CANCEL,
                                                        gtk.RESPONSE_REJECT,
                                                        gtk.STOCK_OK,
                                                        gtk.RESPONSE_ACCEPT)
                                        )
		self._dialog.set_default_response(gtk.RESPONSE_ACCEPT)
                response = self._dialog.run()
		if response == gtk.RESPONSE_ACCEPT:
			self.__downloaddir = self._dialog.get_filename()
			self._dialog.destroy()
	                if self.tree.selected_rows[3] == "DIRECTORY":
        	                iter = self.tree.selected_iter
                	        self._rdownload(iter, self.tree.selected_rows[1])
	                else:
        	                row = self.tree.selected_rows
                	        self.RequestTask(row[3], row[1], row[4])

			return	
		self._dialog.destroy()

	def Download(self, *args, **kwargs):
		self.__downloaddir = None
		if self.tree.selected_rows[3] == "DIRECTORY":
			iter = self.tree.selected_iter
			self._rdownload(iter, self.tree.selected_rows[1])
		else:
			row = self.tree.selected_rows
			self.RequestTask(row[3], row[1], row[4])

	def _rdownload(self, iter, download_to):
		citer = self.tree.treestore.iter_children(iter)
		while citer != None:
			filename = self.tree.treestore.get_value(citer, 1)
			filesize = self.tree.treestore.get_value(citer, 4)
			tth = self.tree.treestore.get_value(citer, 3)
			if tth == "DIRECTORY":
				# Download directory
				self._rdownload(citer, download_to + '/' + filename)
			else:
				# Download file
				self.RequestTask(tth, download_to + '/' + filename, filesize)
			citer = self.tree.treestore.iter_next(citer)
				

        def RequestTask(self, file, localfilename, filesize):
		METADATA = None
		if self.__downloaddir != None:
			METADATA = "DOWNLOADTO:%s"%self.__downloaddir
                self.Event(DCPPEvent("NEED_TASK", (file, localfilename, int(filesize), self._nickname, METADATA)))
                #print "%s, %s, %s, %s"%(file, localfilename, filesize, self._nickname)

	def Close(self, *args, **kwargs):
		pass

        def _magnet(self, *args, **kwargs):
                row = self.tree.selected_rows
		if row[3] == 'DIRECTORY':
                        self.Notify(
                        _('Error'),
                        _("Copy magnet-link can for one selected file, not folder/many files.")
                        )
		else:
	                gtk.Clipboard().set_text(self._genMagnet(row[1], row[4], row[3]))

        def _loadFileList(self, filename):
                self.__temp = '/tmp'
                if os.getenv('TEMP') != None:
                        if os.path.isdir(os.getenv('TEMP')):
                                self.__temp = os.getenv('TEMP')
                os.system('bzcat "%s" > %s/loadfilelist.tmp'%(filename,self.__temp))
                curHandler = SaxHandler()
                parser = make_parser()
                parser.setContentHandler(curHandler)
                try:
                        with_psyco(parser.parse)(open('%s/loadfilelist.tmp'%self.__temp))
                except IOError:
                        print _("Error while parsing %s")%('%s/loadfilelist.tmp'%self.__temp)
                os.remove('%s/loadfilelist.tmp'%self.__temp)
                self._filelist = curHandler.filelist
                # Check for alternates
                try:
                        if self._nickname != self.settings.get('nickname'):
                                for task in self.queue:
                                        if curHandler._alternates.has_key(task.TTH):
                                                task.AddSource(self._nickname, None)
                except:
                        print sys.exc_info()
		start_new_thread(self._background_loading, ())
#		self._background_loading()
		# Load in tree
#		fillpath = '/root'
#		self.psy_calc_size = psyco.proxy(self._calculate_size)
#		rootsize = self.psy_calc_size(fillpath)
#		rootsize = self._calculate_size(fillpath)
#		self._iterlist = {}
#		icon = self.GetIcon('folder')
#		self._iterlist[fillpath] = self.tree.append((icon, fillpath, -1, '', -1))#self.HRS.byteToHuman(rootsize), '', rootsize))
#		self._iterlist[fillpath] = self.tree.append((icon, fillpath, self.HRS.byteToHuman(rootsize), 'DIRECTORY', rootsize))
		# filelist: type, name, filesize, tth
		# tree: icon, file, size, tth, [size in bytes]
#		self._loading(fillpath)


	def _background_loading(self):
                # Load in tree
                fillpath = '/root'
		rootsize = self._calculate_size(fillpath)
#	rootsize = -1
                self._iterlist = {}
#		gtk.gdk.threads_init()
                icon = self.GetIcon('folder')
#               self._iterlist[fillpath] = self.tree.append((icon, fillpath, -1, '', -1))#self.HRS.byteToHuman(rootsize), '', rootsize))
		gtk.gdk.threads_init()
                self._iterlist[fillpath] = self.tree.append((icon, fillpath, self.HRS.byteToHuman(rootsize), 'DIRECTORY', rootsize))
		gtk.gdk.threads_leave()
#		gtk.gdk.threads_leave()
                # filelist: type, name, filesize, tth
                # tree: icon, file, size, tth, [size in bytes]
                self._loading(fillpath)
		if self.__expanditer != None:
			gtk.gdk.threads_init()
			path = self.tree.treestore.get_path(self.__expanditer)
			self.tree.treeview.expand_to_path(path)
			self.tree.treeview.set_cursor(path)
			self.tree.treeview.scroll_to_cell(path)
			gtk.gdk.threads_leave()

	@with_psyco
	def _calculate_size(self, fillpath):
		summary_size = 0
		for elem in self._filelist[fillpath]:
			if int(elem[0]) == 0:
				# Element is directory
				dirsize = self._calculate_size(fillpath + '/' + elem[1])
				elem[2] = dirsize
#				elem.append(dirsize)
				summary_size = summary_size + self._calculate_size(fillpath + '/' + elem[1])
#				summary_size = summary_size + self.psy_calc_size(fillpath + '/' + elem[1])
			else:
				summary_size = summary_size + int(elem[2])
		return summary_size

#	@gtk_lock_required	
	def _loading(self, fillpath):
		for elem in self._filelist[fillpath]:
			if int(elem[0]):
				filesize = int(elem[2])
				tth = elem[3]
				name = elem[1]
				icon = self.GetIcon(name.split('.')[-1])
				row = (icon, name, self.HRS.byteToHuman(filesize), tth, filesize)
				gtk.gdk.threads_init()
				curiter = self.tree.append(row, parent=self._iterlist[fillpath])
				gtk.gdk.threads_leave()
			else:
				name = elem[1]
				icon = self.GetIcon('folder')
#				row = (icon, name, -1, '', -1)#self.HRS.byteToHuman(elem[2]), '', elem[2])
				row = (icon, name, self.HRS.byteToHuman(elem[2]), 'DIRECTORY', elem[2])
				gtk.gdk.threads_init()
				self._iterlist[fillpath + '/' + name] = self.tree.append(row, parent=self._iterlist[fillpath])
				gtk.gdk.threads_leave()
				curiter = self._iterlist[fillpath + '/' + name]
				self._loading(fillpath + '/' + name)
                        try:
                                if self.__expand != None:
                                        if self.__expand == elem[3]:
                                                self.__expanditer = curiter
                        except:
                                pass
			

	def activate(self, *args, **kwargs):
		pass
